package cn.yzgy.yzgyoa.finance.service.impl;

import cn.yzgy.yzgyoa.common.annotation.Syslog;
import cn.yzgy.yzgyoa.common.crsp.StatusCode;
import cn.yzgy.yzgyoa.common.exception.SystemException;
import cn.yzgy.yzgyoa.common.report.ExcelGen;
import cn.yzgy.yzgyoa.common.report.ExcelGenConfig;
import cn.yzgy.yzgyoa.common.service.ISysFileInfoService;
import cn.yzgy.yzgyoa.common.service.impl.SysDictService;
import cn.yzgy.yzgyoa.common.utils.ExportUtil;
import cn.yzgy.yzgyoa.common.utils.SnowflakeIdWorker;
import cn.yzgy.yzgyoa.common.utils.TimeUtil;
import cn.yzgy.yzgyoa.common.utils.ToolsUtil;
import cn.yzgy.yzgyoa.finance.constrant.CapitalFinanceReportsColDef;
import cn.yzgy.yzgyoa.finance.dto.CapitalFinanceRecordDto;
import cn.yzgy.yzgyoa.finance.dto.CapitalFinanceReportDto;
import cn.yzgy.yzgyoa.finance.entity.CapitalFinanceRecord;
import cn.yzgy.yzgyoa.finance.mapper.CapitalFinanceRecordMapper;
import cn.yzgy.yzgyoa.finance.service.ICapitalFinanceRecordService;
import cn.yzgy.yzgyoa.ucenter.entity.UserInfoDetail;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.Synchronized;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Yqsen
 * @since 2021-07-14
 */
@Syslog
@Service
public class CapitalFinanceRecordServiceImpl extends ServiceImpl<CapitalFinanceRecordMapper, CapitalFinanceRecord> implements ICapitalFinanceRecordService {
    /**
     * 事项类型为账户初始化时 CapitalType值为2
     */
    private static final String INIT_CAPITAL_ACCOUNT ="2";

    private SysDictService sysDictService;
    private final ToolsUtil toolsUtil;
    private ISysFileInfoService sysFileInfoService;

    public CapitalFinanceRecordServiceImpl(SysDictService sysDictService, ToolsUtil toolsUtil, ISysFileInfoService sysFileInfoService) {
        this.sysDictService = sysDictService;
        this.toolsUtil = toolsUtil;
        this.sysFileInfoService = sysFileInfoService;
    }

    @Override
    public IPage<CapitalFinanceRecordDto> getAllCapitalDetail(Page<CapitalFinanceRecordDto> capitalFinanceRecordDtoPage, CapitalFinanceRecordDto queryDto) {
        return baseMapper.getAllCapitalDetail(capitalFinanceRecordDtoPage, queryDto);
    }

    @Override
    @Synchronized
    public boolean capitalAdd(UserInfoDetail currentUser, CapitalFinanceRecord queryDto) {
        List<CapitalFinanceRecord> capitalFinanceRecords = new CapitalFinanceRecord().selectList(new QueryWrapper<CapitalFinanceRecord>().lambda()
                .eq(CapitalFinanceRecord::getSource, queryDto.getSource())
                .orderByDesc(CapitalFinanceRecord::getCreateTime)
        );
        //如果该资金渠道无数据 则判断是否为初始化  否则提示初始化
        if(capitalFinanceRecords.size()==0 && !INIT_CAPITAL_ACCOUNT.equals(queryDto.getCapitalType())){
            throw new SystemException(StatusCode.EXCEPTION,"当前资金渠道账户余额未初始化，请初始化当前资金渠道账户余额");
        }
        boolean b = queryDto.setCreateBy(currentUser.getUid()).insert();
        if(!b){
            throw new SystemException(StatusCode.EXCEPTION,"新增收支记录失败");
        }
        b= initAllSurplus(queryDto);
        if(!b){
            throw new SystemException(StatusCode.EXCEPTION,"重新计算所有资金结余出错!");
        }
        return true;
    }

    @Override
    @Synchronized
    public boolean capitalEdit(UserInfoDetail currentUser, CapitalFinanceRecord queryDto) {
        boolean b;
        CapitalFinanceRecord capitalFinanceRecord1 = new CapitalFinanceRecord().selectOne(
                new QueryWrapper<CapitalFinanceRecord>().lambda()
                        .le(CapitalFinanceRecord::getCreateTime, queryDto.getCreateTime()));

        //若该数据非初始化账户数据 则不允许创建时间小于账户初始化时间
        if(capitalFinanceRecord1==null && !INIT_CAPITAL_ACCOUNT.equals(queryDto.getCapitalType())){
            throw new SystemException(StatusCode.EXCEPTION,"当前收支记录发生时间不可小于渠道资金账户初始化时间");
        }
        //原数据
        CapitalFinanceRecord oldCapital= new CapitalFinanceRecord().selectById(queryDto.getFinanceId());
        //渠道
        String source= oldCapital.getSource();

        if(INIT_CAPITAL_ACCOUNT.equals(queryDto.getCapitalType()) && !source.equals(queryDto.getSource())){
            List<CapitalFinanceRecord> capitalFinanceRecords1 = new CapitalFinanceRecord().selectList(
                    new QueryWrapper<CapitalFinanceRecord>().lambda()
                            .eq(CapitalFinanceRecord::getSource, queryDto.getSource()));
            if(capitalFinanceRecords1.size()>1){
                throw new SystemException(StatusCode.EXCEPTION,"当前渠道资金已有收支记录,不可变更渠道！");
            }
        }
        b = queryDto.setModifyTime(LocalDateTime.now()).setModifyBy(currentUser.getUid()).updateById();
        if(!b){
            throw new SystemException(StatusCode.EXCEPTION,"修改数据保存失败！");
        }
        b = initAllSurplus(queryDto);
        if(!b){
            throw new SystemException(StatusCode.EXCEPTION,"重新计算所有资金结余出错！");
        }
        return true;
    }

    @Override
    public boolean capitalDel(String id) {

        List<CapitalFinanceRecord> capitalFinanceRecords = new CapitalFinanceRecord().selectList(
                new QueryWrapper<CapitalFinanceRecord>().lambda()
                        .in(CapitalFinanceRecord::getFinanceId, id)
                        .orderByAsc(CapitalFinanceRecord::getFinanceId));

        for (CapitalFinanceRecord capitalFinanceRecord : capitalFinanceRecords) {
            if (INIT_CAPITAL_ACCOUNT.equals(capitalFinanceRecord.getCapitalType())) {
                List<CapitalFinanceRecord> sourceList = new CapitalFinanceRecord().selectList(
                        new QueryWrapper<CapitalFinanceRecord>().lambda()
                                .eq(CapitalFinanceRecord::getSource, capitalFinanceRecord.getSource()));
                if (sourceList.size() > 1) {
                    throw new SystemException(StatusCode.EXCEPTION, "删除数据中含有渠道资金账户初始化数据，当前渠道资金账户存在收支记录，不允许删除！");
                }
            }
        }
        String[] idStr = id.split(",");
        boolean b;
        int num=0;
        for (String s : idStr) {
            num = baseMapper.deleteById(s);
        }
        if(num<idStr.length){
          return false;
        }
        //删除上传的票据
        sysFileInfoService.delFiles(id);

        b = initAllSurplus(capitalFinanceRecords.get(0));

        return b;
    }

    @Override
    public String exportCapitalRecord(CapitalFinanceRecordDto queryDto, UserInfoDetail currentUser) {
        //如果未选择时间范围，则不对时间进行处理
        getCapitalFinanceDate(queryDto);
        //获取组装查询条件
        StringBuilder stringBuilder = ExportUtil.getQueryCondition(queryDto);
        // 获取数据
        List<JSONObject> jsonList = sysDictService.injectDictList(baseMapper.getAllCapitalDetail(queryDto));
        List<CapitalFinanceReportDto> res = new ArrayList<>();
        CapitalFinanceReportDto cap;
        for (JSONObject jsonObject : jsonList) {
            cap = JSON.toJavaObject(jsonObject, CapitalFinanceReportDto.class);

            res.add(cap);
        }
        res.forEach(x->x.setInOrOut("true".equals(x.getInOrOut()) ?"收入":"支出"));


        String reportId = String.format("%d", SnowflakeIdWorker.getNext());

        // 生成标题
        String title = String.format("重庆市钰圳广越商贸有限公司-收支明细记录统计报表-%s", TimeUtil.getCurrentTimeString(TimeUtil.YMD_TIME_FORMAT_STRING));
        String filePath = System.getProperty("user.dir") + "/report/";
        String fileName = String.format("收支明细记录统计报表-%s-%d-%s.xls",
                TimeUtil.getCurrentTimeString(TimeUtil.NO_SEPARATOR_TIME_FORMAT_STRING), currentUser.getUid(), reportId);
        String desc;
        desc=String.format("原始文件名：%s  生成时间：%s\r\n" +
                        "创建人：%s(%s)  总计条目数：%d 条 \r\n" +
                        "%s",
                fileName, TimeUtil.getCurrentTimeString(),
                currentUser.getUserName(), currentUser.getUid(), res.size(),
                stringBuilder.toString());


        // 生成excel
        ExcelGen<CapitalFinanceReportDto> excelGen = new ExcelGen<>(new ExcelGenConfig()
                .setFilePath(filePath)
                .setFileName(fileName)
                .setSecondTitle(desc)
                .setDocumentTitle(title), CapitalFinanceReportsColDef.getCOL_CONFIGS(), res);
        return ExportUtil.createAndInsert(excelGen,currentUser);
    }


    /**
     * 提取时间不为空的判定
     * @param queryDto 查询对象
     */
    private void getCapitalFinanceDate(CapitalFinanceRecordDto queryDto) {
        //如果未选择时间范围，则不对时间进行处理
        if (queryDto.getStartTime() != null && queryDto.getEndTime() != null) {
            String startTime = queryDto.getStartTime().replace("+", " ").replace("%3A", ":");
            String endTime = queryDto.getEndTime().replace("+", " ").replace("%3A", ":");
            queryDto.setStartDate(toolsUtil.toLocalDateTime(startTime));
            queryDto.setEndDate(toolsUtil.toLocalDateTime(endTime));
            //去除前端传入时间参数
            queryDto.setStartTime(null);
            queryDto.setEndTime(null);
        }
    }

    private boolean initAllSurplus(CapitalFinanceRecord queryDto) {
        boolean state = false;

        //参照值 从这一条数据的前一条往后重新计算总账资金结余
        CapitalFinanceRecord capitalFinanceRecord = new CapitalFinanceRecord().selectOne(
                new QueryWrapper<CapitalFinanceRecord>()
                        .lambda()
                        .lt(queryDto.getCreateTime() != null, CapitalFinanceRecord::getCreateTime, queryDto.getCreateTime())
                        .orderByDesc(CapitalFinanceRecord::getCreateTime).last("limit 1"));

        BigDecimal allSurplus = BigDecimal.ZERO;
        if(capitalFinanceRecord!=null){
            allSurplus = capitalFinanceRecord.getAllSurplus();
        }

        //总账记录List
        List<CapitalFinanceRecord> allCapitalList = new CapitalFinanceRecord().selectList(
                new QueryWrapper<CapitalFinanceRecord>()
                        .lambda()
                        .ge(queryDto.getCreateTime()!=null,CapitalFinanceRecord::getCreateTime,queryDto.getCreateTime())
                        .orderByAsc(CapitalFinanceRecord::getCreateTime)
        );
        CapitalFinanceRecord temp;

        for (CapitalFinanceRecord capitalFinanceRecord1 : allCapitalList) {
            temp = capitalFinanceRecord1;
            //若记录为收入
            if (temp.getInOrOut()) {
                temp.setAllSurplus(allSurplus.add(temp.getAmountOfMoney()));
                allSurplus = temp.getAllSurplus();
                state = temp.updateById();
            } else {
                temp.setAllSurplus(allSurplus.subtract(temp.getAmountOfMoney()));
                allSurplus = temp.getAllSurplus();
                state = temp.updateById();
            }
        }

        //参照值 从这一条数据往后重新计算渠道资金结余
        CapitalFinanceRecord sourCapital = new CapitalFinanceRecord().selectOne(
                new QueryWrapper<CapitalFinanceRecord>()
                        .lambda()
                        .lt(queryDto.getCreateTime() != null, CapitalFinanceRecord::getCreateTime, queryDto.getCreateTime())
                        .eq(CapitalFinanceRecord::getSource,queryDto.getSource())
                        .orderByDesc(CapitalFinanceRecord::getCreateTime).last("limit 1"));

        BigDecimal surplus = BigDecimal.ZERO;
        if(sourCapital!=null){
            surplus= sourCapital.getSurplus();
        }
        //渠道记录List
        List<CapitalFinanceRecord> sourceCapitalList = new CapitalFinanceRecord().selectList(
                new QueryWrapper<CapitalFinanceRecord>()
                        .lambda()
                        .ge(queryDto.getCreateTime()!=null,CapitalFinanceRecord::getCreateTime,queryDto.getCreateTime())
                        .eq(CapitalFinanceRecord::getSource,queryDto.getSource())
                        .orderByAsc(CapitalFinanceRecord::getCreateTime)
        );
        for (CapitalFinanceRecord capitalFinanceRecord1 : sourceCapitalList) {
            temp = capitalFinanceRecord1;
            //若记录为收入
            if (temp.getInOrOut()) {
                temp.setSurplus(surplus.add(temp.getAmountOfMoney()));
                surplus = temp.getSurplus();
                state = temp.updateById();
            } else {
                temp.setSurplus(surplus.subtract(temp.getAmountOfMoney()));
                surplus = temp.getSurplus();
                state = temp.updateById();
            }
        }

        return state;
    }
}
